.compile-assets-base:
  extends:
    - .default-retry
    - .default-before_script
    - .assets-compile-cache
  image: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images/debian-${DEBIAN_VERSION}-ruby-${RUBY_VERSION}-node-18.16:rubygems-${RUBYGEMS_VERSION}-git-2.33-lfs-2.9-yarn-1.22-graphicsmagick-1.3.36
  variables:
    SETUP_DB: "false"
    WEBPACK_VENDOR_DLL: "true"
    # Disable warnings in browserslist which can break on backports
    # https://github.com/browserslist/browserslist/blob/a287ec6/node.js#L367-L384
    BROWSERSLIST_IGNORE_OLD_DATA: "true"
    WEBPACK_COMPILE_LOG_PATH: "tmp/webpack-output.log"
  stage: prepare
  script:
    - yarn_install_script
    - export GITLAB_ASSETS_HASH=$(bin/rake gitlab:assets:hash_sum)
    - 'echo "CACHE_ASSETS_AS_PACKAGE: ${CACHE_ASSETS_AS_PACKAGE}"'
    # The new strategy to cache assets as generic packages is experimental and can be disabled by removing the `CACHE_ASSETS_AS_PACKAGE` variable
    - |
      if [[ "${CACHE_ASSETS_AS_PACKAGE}" == "true" ]]; then
        source scripts/gitlab_component_helpers.sh

        if ! gitlab_assets_archive_doesnt_exist; then
          # We remove all assets from the native cache as they could pollute the fresh assets from the package
          rm -rf public/assets/ app/assets/javascripts/locale/**/app.js
          run_timed_command "download_and_extract_gitlab_assets"
        fi
      fi
    - assets_compile_script
    - echo -n "${GITLAB_ASSETS_HASH}" > "cached-assets-hash.txt"

compile-production-assets:
  extends:
    - .compile-assets-base
    - .production
    - .frontend:rules:compile-production-assets
  artifacts:
    name: webpack-report
    expire_in: 31d
    paths:
      # These assets are used in multiple locations:
      # - in `build-assets-image` job to create assets image for packaging systems
      # - GitLab UI for integration tests: https://gitlab.com/gitlab-org/gitlab-ui/-/blob/e88493b3c855aea30bf60baee692a64606b0eb1e/.storybook/preview-head.pug#L1
      - cached-assets-hash.txt
      - public/assets/
      - "${WEBPACK_COMPILE_LOG_PATH}"
    when: always
  after_script:
    - rm -f /etc/apt/sources.list.d/google*.list  # We don't need to update Chrome here

compile-production-assets as-if-foss:
  extends:
    - compile-production-assets
    - .as-if-foss
    - .frontend:rules:compile-production-assets-as-if-foss

compile-test-assets:
  extends:
    - .compile-assets-base
    - .frontend:rules:compile-test-assets
  artifacts:
    expire_in: 7d
    paths:
      - public/assets/
      - node_modules/@gitlab/svgs/dist/icons.json  # app/helpers/icons_helper.rb uses this file
      - "${WEBPACK_COMPILE_LOG_PATH}"
    when: always

compile-test-assets as-if-foss:
  extends:
    - compile-test-assets
    - .frontend:rules:compile-test-assets-as-if-foss
    - .as-if-foss

update-assets-compile-production-cache:
  extends:
    - compile-production-assets
    - .assets-compile-cache-push
    - .shared:rules:update-cache
  stage: prepare
  artifacts: {}  # This job's purpose is only to update the cache.

update-assets-compile-test-cache:
  extends:
    - compile-test-assets
    - .assets-compile-cache-push
    - .shared:rules:update-cache
  stage: prepare
  script:
    - !reference [compile-test-assets, script]
    - echo -n "${GITLAB_ASSETS_HASH}" > "cached-assets-hash.txt"
  artifacts: {}  # This job's purpose is only to update the cache.

update-storybook-yarn-cache:
  extends:
    - .default-retry
    - .default-utils-before_script
    - .storybook-yarn-cache-push
    - .shared:rules:update-cache
  stage: prepare
  script:
    - yarn_install_script

retrieve-frontend-fixtures:
  variables:
    SETUP_DB: "false"
  extends:
    - .default-retry
    - .frontend:rules:default-frontend-jobs
  stage: prepare
  script:
    - source scripts/utils.sh
    - source scripts/gitlab_component_helpers.sh
    - install_gitlab_gem
    - export_fixtures_sha_for_download
    - |
      if check_fixtures_download; then
        run_timed_command "download_and_extract_fixtures"
      fi
  artifacts:
    paths:
      - tmp/tests/frontend/

# Download fixtures only when a merge request contains changes to only JS files
# and fixtures are present in the package registry.
.frontend-fixtures-base:
  extends:
    - .default-retry
    - .default-before_script
    - .rails-cache
    - .use-pg13
  stage: fixtures
  needs: ["setup-test-env", "retrieve-tests-metadata", "retrieve-frontend-fixtures"]
  variables:
    # Don't add `CRYSTALBALL: "false"` here as we're enabling Crystalball for scheduled pipelines (in `.gitlab-ci.yml`), so that we get coverage data
    # for the `frontend fixture RSpec files` that will be added to the Crystalball mapping in `update-tests-metadata`.
    # More information in https://gitlab.com/gitlab-org/gitlab/-/merge_requests/74003.
    WEBPACK_VENDOR_DLL: "true"
  script:
    - source scripts/gitlab_component_helpers.sh
    - |
      if check_fixtures_reuse; then
        echoinfo "INFO: Reusing frontend fixtures from 'retrieve-frontend-fixtures'."
        exit 0
      fi
    - run_timed_command "gem install knapsack --no-document"
    - section_start "gitaly-test-spawn" "Spawning Gitaly"; scripts/gitaly-test-spawn; section_end "gitaly-test-spawn";  # Do not use 'bundle exec' here
    - source ./scripts/rspec_helpers.sh
    - rspec_paralellized_job
  artifacts:
    name: frontend-fixtures
    expire_in: 31d
    when: always
    paths:
      - tmp/tests/frontend/
      - knapsack/
      - crystalball/

# Builds FOSS, and EE fixtures in the EE project.
# Builds FOSS fixtures in the FOSS project.
rspec-all frontend_fixture:
  extends:
    - .frontend-fixtures-base
    - .frontend:rules:default-frontend-jobs
  needs:
    - !reference [.frontend-fixtures-base, needs]
    - "compile-test-assets"
  parallel: 7

# Builds FOSS fixtures in the EE project, with the `ee/` folder removed (due to `as-if-foss`).
rspec-all frontend_fixture as-if-foss:
  extends:
    - .frontend-fixtures-base
    - .frontend:rules:frontend_fixture-as-if-foss
    - .as-if-foss
  variables:
    # We explicitely disable Crystalball here so as even in scheduled pipelines we don't need it since it's already enabled for `rspec-all frontend_fixture` there.
    CRYSTALBALL: "false"
    WEBPACK_VENDOR_DLL: "true"
    KNAPSACK_GENERATE_REPORT: ""
    FLAKY_RSPEC_GENERATE_REPORT: ""
  needs:
    - !reference [.frontend-fixtures-base, needs]
    - "compile-test-assets as-if-foss"

# Uploads EE fixtures in the EE project.
# Uploads FOSS fixtures in the FOSS project.
upload-frontend-fixtures:
  extends:
    - .frontend-fixtures-base
    - .frontend:rules:upload-frontend-fixtures
  stage: fixtures
  needs: ["rspec-all frontend_fixture"]
  script:
    - source scripts/utils.sh
    - source scripts/gitlab_component_helpers.sh
    - export_fixtures_sha_for_upload
    - 'fixtures_archive_doesnt_exist || { echoinfo "INFO: Exiting early as package exists."; exit 0; }'
    - run_timed_command "create_fixtures_package"
    - run_timed_command "upload_fixtures_package"
  artifacts: {}

graphql-schema-dump:
  variables:
    SETUP_DB: "false"
  extends:
    - .default-retry
    - .rails-cache
    - .default-before_script
    - .frontend:rules:default-frontend-jobs
  stage: fixtures
  needs: []
  script:
    - bundle exec rake gitlab:graphql:schema:dump
  artifacts:
    name: graphql-schema
    paths:
      - tmp/tests/graphql/gitlab_schema.graphql
      - tmp/tests/graphql/gitlab_schema.json

graphql-schema-dump as-if-foss:
  extends:
    - graphql-schema-dump
    - .frontend:rules:default-frontend-jobs-as-if-foss
    - .as-if-foss

.frontend-test-base:
  extends:
    - .default-retry
    - .yarn-cache
  variables:
    # Disable warnings in browserslist which can break on backports
    # https://github.com/browserslist/browserslist/blob/a287ec6/node.js#L367-L384
    BROWSERSLIST_IGNORE_OLD_DATA: "true"
    USE_BUNDLE_INSTALL: "false"
    SETUP_DB: "false"
  before_script:
    - !reference [.default-before_script, before_script]
    - yarn_install_script
  stage: test

.jest-base:
  extends: .frontend-test-base
  script:
    - run_timed_command "yarn jest:ci"

jest:
  extends:
    - .jest-base
    - .frontend:rules:jest
  needs: ["rspec-all frontend_fixture"]
  artifacts:
    name: coverage-frontend
    expire_in: 31d
    when: always
    paths:
      - coverage-frontend/
      - junit_jest.xml
      - tmp/tests/frontend/
    reports:
      junit: junit_jest.xml
  parallel: 7

jest predictive:
  extends:
    - jest
    - .frontend:rules:jest:predictive
  needs:
    - !reference [jest, needs]
    - "detect-tests"
  script:
    - if [[ -s "$RSPEC_CHANGED_FILES_PATH" ]] || [[ -s "$RSPEC_MATCHING_JS_FILES_PATH" ]]; then run_timed_command "yarn jest:ci:predictive"; fi

jest as-if-foss:
  extends:
    - .jest-base
    - .frontend:rules:jest:as-if-foss
    - .as-if-foss
  needs: ["rspec-all frontend_fixture as-if-foss"]
  parallel: 4

jest predictive as-if-foss:
  extends:
    - .jest-base
    - .frontend:rules:jest:predictive:as-if-foss
    - .as-if-foss
  needs:
    - "rspec-all frontend_fixture as-if-foss"
    - "detect-tests"
  script:
    - if [[ -s "$RSPEC_CHANGED_FILES_PATH" ]] || [[ -s "$RSPEC_MATCHING_JS_FILES_PATH" ]]; then run_timed_command "yarn jest:ci:predictive"; fi

jest-integration:
  extends:
    - .frontend-test-base
    - .frontend:rules:default-frontend-jobs
  script:
    - run_timed_command "yarn jest:integration --ci"
  needs: ["rspec-all frontend_fixture", "graphql-schema-dump"]

coverage-frontend:
  extends:
    - .default-retry
    - .default-utils-before_script
    - .yarn-cache
    - .frontend:rules:coverage-frontend
  needs:
    - job: "jest"
      optional: true
    - job: "jest predictive"
      optional: true
  stage: post-test
  script:
    - yarn_install_script
    - run_timed_command "yarn node scripts/frontend/merge_coverage_frontend.js"
    # Removing the individual coverage results, as we just merged them.
    - if ls coverage-frontend/jest-* > /dev/null 2>&1; then
        rm -r coverage-frontend/jest-*;
      fi
  coverage: '/^Statements\s*:\s*?(\d+(?:\.\d+)?)%/'
  artifacts:
    name: coverage-frontend
    expire_in: 31d
    paths:
      - coverage-frontend/
    reports:
      coverage_report:
        coverage_format: cobertura
        path: coverage-frontend/cobertura-coverage.xml

webpack-dev-server:
  extends:
    - .default-retry
    - .default-utils-before_script
    - .yarn-cache
    - .frontend:rules:default-frontend-jobs
  stage: test
  needs: []
  variables:
    WEBPACK_MEMORY_TEST: "true"
    WEBPACK_VENDOR_DLL: "true"
  script:
    - yarn_install_script
    - run_timed_command "retry yarn webpack-vendor"
    - run_timed_command "node --expose-gc node_modules/.bin/webpack-dev-server --config config/webpack.config.js"
  artifacts:
    name: webpack-dev-server
    expire_in: 31d
    paths:
      - webpack-dev-server.json

bundle-size-review:
  extends:
    - .default-retry
    - .default-utils-before_script
    - .assets-compile-cache
    - .frontend:rules:bundle-size-review
  image: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images:danger
  stage: test
  needs: []
  script:
    - yarn_install_script
    - scripts/bundle_size_review
  artifacts:
    when: always
    name: bundle-size-review
    expire_in: 31d
    paths:
      - bundle-size-review/

.startup-css-check-base:
  extends:
    - .frontend-test-base
  script:
    - run_timed_command "yarn generate:startup_css"
    - yarn check:startup_css

startup-css-check:
  extends:
    - .startup-css-check-base
    - .frontend:rules:default-frontend-jobs
  needs: ["compile-test-assets", "rspec-all frontend_fixture"]

startup-css-check as-if-foss:
  extends:
    - .startup-css-check-base
    - .as-if-foss
    - .frontend:rules:default-frontend-jobs-as-if-foss
  needs:
    - job: "compile-test-assets as-if-foss"
    - job: "rspec-all frontend_fixture as-if-foss"

.compile-storybook-base:
  extends:
    - .frontend-test-base
    - .storybook-yarn-cache
  script:
    - run_timed_command "retry yarn run storybook:install --frozen-lockfile"
    - run_timed_command "yarn run storybook:build"
  needs: ["graphql-schema-dump"]

compile-storybook:
  extends:
    - .compile-storybook-base
    - .frontend:rules:default-frontend-jobs
  needs:
    - !reference [.compile-storybook-base, needs]
    - job: "rspec-all frontend_fixture"
  artifacts:
    name: storybook
    expire_in: 31d
    when: always
    paths:
      - storybook/public

compile-storybook as-if-foss:
  extends:
    - .compile-storybook-base
    - .as-if-foss
    - .frontend:rules:default-frontend-jobs-as-if-foss
  needs:
    - job: "graphql-schema-dump as-if-foss"
    - job: "rspec-all frontend_fixture as-if-foss"
